package chain

import (
	"awesomeProject1/pkg/chain"
	"context"
	"fmt"
	"github.com/simplechain-org/client/log"
	"github.com/simplechain-org/go-simplechain/core/types"
	"sync/atomic"
	"time"
)

func (s *service) BlockNumber() (uint64, error) {
	if s.isSubscribeNewHead {
		return s.blockNumber, nil
	}
	blockNumber, err := s.chainClient.BlockNumber()
	if err != nil {
		return 0, err
	}
	return blockNumber, nil
}

func (s *service) BlockTime() (uint64, error) {
	if s.isSubscribeNewHead {
		return s.blockTime, nil
	}
	blockNumber, err := s.chainClient.BlockNumber()
	if err != nil {
		return 0, err
	}
	header, err := s.chainClient.GetHeaderByNumber(fmt.Sprintf("0x%x", blockNumber))
	if err != nil {
		return 0, err
	}
	return header.Time, nil
}

func (s *service) GetBlockByBlockNumOrHash(input string) (*chain.Block, error) {
	return s.chainClient.GetBlockByBlockNumOrHash(input)
}

func (s *service) GetHeaderByNumber(number string) (*types.Header, error) {
	return s.chainClient.GetHeaderByNumber(number)
}

// subscribeNewHead 订阅新区块头消息
func (s *service) subscribeNewHead() {
	ch := make(chan *types.Header, 10)
	subscription, err := s.chainClient.GetEthClient().SubscribeNewHead(context.Background(), ch)
	if err != nil {
		log.Error("chain service subscribeNewHead", "err", err.Error())
		return
	}
	go func() {
		for {
			select {
			case <-s.stop:
				log.Info("chain service subscribeNewHead exits")
				return
			case header := <-ch:
				if header != nil {
					s.blockNumber = header.Number.Uint64()
					s.blockTime = header.Time
					log.Debug("chain service update blockNumber", "number", s.blockNumber, "timestamp", s.blockTime, "id", s.Id)
				}
			case err := <-subscription.Err():
				if err != nil {
				loop:
					for {
						select {
						case <-s.stop:
							log.Info("chain service subscribeNewHead exits")
							return
						default:
							//连接断开以后，需要重新进行订阅，虽然chainSimpleClient自身有重连操作，但不会自动重新订阅
							subscription, err = s.chainClient.GetEthClient().SubscribeNewHead(context.Background(), ch)
							if err != nil {
								time.Sleep(time.Second * 5)
							} else {
								break loop
							}
						}
					}
				}
			}
		}
	}()
}

func (s *service) Stop() {
	if atomic.CompareAndSwapUint32(&s.isStop, 0, 1) {
		close(s.stop)
	}
}
